#include "SSequencer.h"
#include "SConfig.h"
#include "CImage.h"
#include "CView.h"
#include "SRenderer.h"
#include "system.h"
#include <string>

using namespace std;

DEFINE_SINGLETON(SSequencer);

//----------------------------------------------
SSequencer::SSequencer()
{
	m_oFiles.reserve(DEFAULT_NB_RESERVED_FILE_INFOS);
	m_oImageShowTimer.setSequencer(this);
}

//----------------------------------------------
SSequencer::~SSequencer()
{
	clearFileList();
}

//----------------------------------------------
void SSequencer::update()
{
}

//----------------------------------------------
void SSequencer::clearFileList()
{
	for (vector<CFileInfo*>::const_iterator it = m_oFiles.begin(); it != m_oFiles.end(); it++)
		delete *it;
	m_oFiles.clear();
}

//----------------------------------------------
void SSequencer::loadFileList()
{
	clearFileList();
	loadFileListFromDir(SConfig::instance()->m_sImagesDir.c_str());
	onFileListReady();
}

//----------------------------------------------
void SSequencer::onFileListReady()
{

}

//----------------------------------------------
void SSequencer::loadFileListFromDir(const xstring& sDir)
{
	HANDLE			hFile;
	xstring			sPattern;
	xstring			sFilePath;
	WIN32_FIND_DATA	oWin32FileInfo;

	sPattern	= sDir;
	sPattern	+= CSTR("\\*.*");
	hFile		= FindFirstFile(sPattern.c_str(), &oWin32FileInfo);

	if (hFile != INVALID_HANDLE_VALUE)
	{
		do
		{
			// Not '.' or '..'
			if (oWin32FileInfo.cFileName[0] != CSTR('.'))
			{
				sFilePath = sDir;
				sFilePath += CSTR("\\");
				sFilePath += oWin32FileInfo.cFileName;

				// Directory
				if (oWin32FileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
				{
					loadFileListFromDir(sFilePath);
				}
				// File
				else
				{
					const EImageType eImageType = CImage::getImageType(sFilePath);
					if (eImageType != E_NOT_A_VALID_IMAGE_TYPE)
					{
						CFileInfo* pFileInfo = new CFileInfo(sFilePath.c_str());
						pFileInfo->m_eImageType = eImageType;
						m_oFiles.push_back( pFileInfo );
					}
				}
			}
		} while (FindNextFile(hFile, &oWin32FileInfo) == TRUE);

		FindClose(hFile);
	}
}

//----------------------------------------------
bool SSequencer::loadNextFile()
{
	int iFileCount = m_oFiles.size();

	int iIndex = 0;

	// Find an image not in the history (randomly)
	for (int i=0; i < MAX_SHUFFLE_ITERATION_COUNT; i++)
	{
		iIndex = (int)((float)(iFileCount) * (float)rand() / (RAND_MAX + 1.f)); // we use the higher bits of the rand() value (some implementations are not equals in odds)
		assert(iIndex < (int)m_oFiles.size());
		CFileInfo* pFileInfo = m_oFiles[iIndex];
		assert(pFileInfo != NULL);
		if (!imageAlreadyInHistory(*pFileInfo))
			break;
	}

	// Try to load it or increment in the file list to find a valid file
	bool bLoaded = false;
	CFileInfo* pFileInfo = m_oFiles[iIndex];
	for (int i=0; !bLoaded && i < MAX_SHUFFLE_ITERATION_COUNT; i++)
	{
		pFileInfo = m_oFiles[iIndex];
		assert(pFileInfo != NULL);

		// Load image from HD
		bLoaded = m_oImagePool.loadNewImage(*pFileInfo);

		// Load texture in vram
		if (bLoaded)
		{
			bLoaded = SRenderer::instance()->loadTexture(pFileInfo->m_oImage);
		}
		if (!bLoaded)
		{
			iIndex++;
			iIndex %= iFileCount;
		}
	}

	if (bLoaded)
	{
		//CImage* pImage = NULL;
		m_oPathHashHistory.push(pFileInfo->m_oPath.getHash());
		log(pFileInfo->m_oPath.c_str());
		log(CSTR("\n"));

		return true;
	}

	return false;
}

//----------------------------------------------
bool SSequencer::imageAlreadyInHistory	(const CFileInfo& oFileInfo) const
{
	int i = 0;
	for (THistory::const_reverse_iterator it = m_oPathHashHistory.rbegin(); it != m_oPathHashHistory.rend() && i < m_oPathHashHistory.size(); it++, i++)
	{
		if (oFileInfo.m_oPath == (*it))
			return true;
	}

	return false;
}

//----------------------------------------------
void SSequencer::changeCurrentImage()
{
}

//----------------------------------------------
void SSequencer::run()
{
	m_oImageShowTimer.start();
}

//----------------------------------------------
void SSequencer::onImageShowTimer()
{
	loadNextFile();
	changeCurrentImage();
}

//----------------------------------------------
void SSequencer::CTimerImageShow::onTimer()
{
	assert( m_sequencer != NULL );
	m_sequencer->onImageShowTimer();
}
